Printing is among the most complicated tasks that a Windows application programmer undertakes. Fortunately, you are using Visual Basic. Visual Basic makes printing relatively easy by hiding most of the complexity of the Windows API.
This chapter explores printing with Visual Basic by focusing on the Print dialog box, Microsoft Word, and the Printer object.
The dialog box in Figure 12.1 is an example of the Print common dialog box. It allows the user to select a printer, change its properties, select a range of pages to print, and specify the number of copies. If needed, you can modify the dialog box in
various ways. For example, you could disable or hide the Print To File check box.
Figure 12.1. The Print common dialog box.
In the following example, the Print dialog box appears on-screen when the user clicks the File | Print menu option. The steps to create the example follow:
Figure 12.2. The Common Dialogs Control Properties dialog box.
You can customize the Print dialog box by setting the Flags property of the common dialog control. Table 12.1. shows the constants you can use to set the Flags property.
Constant |
Description |
cdlPDAllPages |
Selects the All Pages option button, which is the default. |
cdlPDPageNums |
Selects the Pages option button. This constant only works if the Max property of the common dialog control is greater than 0. |
cdlPDNoPageNums |
Disables the Pages option button and the associated edit control. |
cdlPDSelection |
Selects the Selection option button. |
cdlPDNoSelection |
Disables the Selection option button. |
cdlPDCollate |
Checks the Collate check box. |
cdlPDPrintToFile |
Checks the Print To File check box. |
cdlPDDisablePrintToFile |
Disables the Print To File check box. |
cdlPDHidePrintToFile |
Hides the Print To File check box. |
For example, if you wanted to have the Print to Disk check box checked, the All Pages option button selected, and the Selection option button disabled, you would use the following two lines in the click method of the Print menu option:
CommonDialog1.Flags = cdlPDAllPages Or cdlPDPrintToFile _ or cdlPDNoSelection CommonDialog1.ShowPrinter
Some of the constants shown in Table 12.1 are mutually exclusive. For example, cldPDAllPages, cdlPDPageNums, and cdlPDSelection all affect the same group of option buttons. You should only use one of them at a time.
In order to enable the user to enter beginning and ending page numbers or to select the Collate check box, you must set the Max property of the common dialog box. Assuming that your document has seven pages, you could invoke the Print dialog box in the
following manner:
CommonDialog1.Flags = cdlPDPageNums Or cdlPDPrintToFile _ or cdlPDNoSelection CommonDialog1.MAX = 6 CommonDialog1.FromPage = 0 CommonDialog1.ToPage = CommonDialog1.MAX CommonDialog1.ShowPrinter
You can find additional information about the constants used to set the Flags property by using the Object Browser in the Microsoft Common Dialog Control library or using the term Flags and looking under the topic Flags Property (Print Dialog) in the
Visual Basic help file.
After the Print dialog box appears on-screen, the user makes his or her selections and then clicks on OK or Cancel. You can then retrieve the information that the user entered. Before discussing the information, let's look at the case where the user
clicks the Cancel button.
You can handle the Cancel button in two different ways. You can ignore it, or you can have Visual Basic generate an error that you can trap. To have Visual Basic generate an error, use the following lines of code:
On Error goto CancelPrtDlg CommonDialog1.CancelError = True CommonDialog1.ShowPrinter ' Do stuff with user input ' print document ' exit routine CancelPrtDlg: If Err.Number = 32755 Then ' handle cancel button end if ' handle other errors ' exit routine
The second line in the preceding code sets the CancelError property to True. Then, the dialog box is displayed using the ShowPrinter method. If the user cancels the dialog box, the code immediately after the CancelPrtDlg label will be called. Otherwise,
the document would be printed.
When Visual Basic returns control to your program after the user clicks OK, several properties of the common dialog control will have been set. To find out whether the user selected to print all pages or a range of pages, use the following lines of
code:
Dim pagesAll As Boolean Dim pagesSome As Boolean Dim pagesSelection As Boolean pagesAll = (CommonDialog1.Flags And cdlPDAllPages) = cdlPDAllPages pagesSome = (CommonDialog1.Flags And cdlPDPageNums) = cdlPDPageNums pagesSelection = (CommonDialog1.Flags And cdlPDSelection) = cdlPDSelection
By using the logical AND operator, you can extract the information about a specific flag from the Flags property. When the All Pages option button is selected, PagesAll is True, and the rest of the properties are False. When the Selection option button
is selected, PagesSelection is True, and the rest of the properties are False. If you have disabled or hidden the Page Range or Selection option buttons, you don't need to test for them.
You can test the Print to File check box with the following lines of code:
Dim printToFile As Boolean printToFile = (CommonDialog1.Flags And cdlPDPrintToFile) = cdlPDPrintToFile
If the Print to File check box is checked, then PrintToFile is True; otherwise, it is False.
In a similar fashion, you can test the Collate check box with the following lines of code:
Dim collate As Boolean collate = (CommonDialog1.Flags And cdlPDCollate) = cdlPDCollate
If the Collate check box is checked, then Collate is True; otherwise, it is False.
Getting the rest of the information is very straightforward. Simply look at the FromPage and ToPage properties of the common dialog control. You can retrieve the number of copies that the user selected by looking at the value of Printer.Copies.
Thanks to Microsoft Word's OLE interface, you can take a side trip from Visual Basic and look at ways to cheat when printing. Instead of developing routines to read a file, perform word wrap, handle columns, display a print preview, and print a
document, you can let Microsoft Word do the work. And if you keep Microsoft Word minimized, your user might never know!
The first step to using Microsoft Word is to allocate an object and create an instance of word.basic. To perform this step, use the following code:
Private Sub Form_Load() Dim msword As Object Set msword = CreateObject("word.basic") ... ' do things with the msword object. ... Set msword = Nothing End Sub
You can use the msword object to send WordBasic statements to Microsoft Word for execution. For example, the following lines of code will print two copies of the config.sys file:
Private Sub Form_Load() Dim msword As Object Set msword = CreateObject("word.basic") With msword .AppMaximize .FileOpen Name:="c:\config.sys", AddToMru:=0 .FilePrint Background:=1, Type:=0, NumCopies:=2 End With Set msword = Nothing End Sub
You can manipulate multiple documents at once by creating more objects in the Word.basic class.
The WRDBASIC.HLP file that comes with Microsoft Word is complete. However, the
syntax that is used to call the WordBasic function in Visual Basic is slightly different than the one shown in the help file.
You need to be aware of two differences. The first is that parameters do not need a leading period. The second is that the assignment operator for named arguments in Visual Basic is ':='. For example, the help file topic that discusses FilePrint shows
the syntax as
FilePrint [.Background = number] [, .Type = number] [, .NumCopies = number]
The corresponding Visual Basic statement is
msword.FilePrint Background:=1, Type:=0, NumCopies:=2
You can see that the changes are easy to handle.
Listing 12.1 contains methods that enable you to create a new Microsoft Word document based on the Letter2 template. This project contains a form with a text control in which the user enters the main text of a letter. After entering the text, the user
clicks a command button, and Microsoft Word starts. The information from the user is combined with the Letter2 template to produce a printed page.
To run the example program in Listing 12.1, follow these steps:
Dim msword As Object Private Sub wordDelLineWith(oldStuff As String) msword.StartOfDocument msword.EditFind Find:=oldStuff, Direction:=0, MatchCase:=0, _ WholeWord:=0, PatternMatch:=0, SoundsLike:=0, Format:=0, Wrap:=0 msword.StartOfLine msword.EndOfLine 1 msword.EditClear End Sub Private Sub wordReplace(oldStuff As String, newStuff As String) msword.StartOfDocument msword.EditReplace oldStuff, newStuff, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 End Sub Private Sub Command1_Click() Set msword = CreateObject("word.basic") With msword .AppMaximize .FileNew Template:="Letter2", NewTemplate:=0 End With ' Replace all of the easy stuff. This is all fixed information wordReplace "[Company Name]", "Barside Brewery" wordReplace "[Street Address]", "123 Lite Road" wordReplace "[City, State/Province Zip/Postal Code]", "Pub City, Montana _43255" wordReplace "[Recipient Name]", "Jack Tremor" wordReplace "[Address]", "1414 Runner Drive" wordReplace "[City, State/Province Zip/Postal Code]", "Boston, MASS 12321" wordReplace "[Recipient]", "Jack" wordReplace "[Your name]", "Rose Switz" wordReplace "[Your position]", "Shipping Coordinator" wordReplace "[Typist's initials]", "dmm" wordReplace "[Number]", "0" wordDelLineWith "cc:" wordDelLineWith "[Type" With msword .INSERT Text1.TEXT .InsertPara .FilePrint .FileClose 2 End With Set msword = Nothing End Sub Private Sub Form_Load() Label1.AutoSize = True Label1.Caption = "Enter the body of the letter below and then click on PRINT." Label1.Height = 200 Label1.Left = 50 Label1.TOP = 50 ' Note that this control must be set as ' MultiLine=True & ScollBars=2 through ' the properties dialog box at design time. Text1.Height = 3000 Text1.Left = 200 Text1.TEXT = "" Text1.TabIndex = 1 Text1.TOP = Label1.TOP + Label1.Height + 100 Text1.Width = 4000 Command1.Caption = "Print Letter" Command1.Height = 500 Command1.Left = 50 Command1.TabIndex = 2 Command1.TOP = 3500 Command1.Width = 4500 Form1.Caption = "Letter Entry" Form1.Height = 4500 Form1.Width = 4700 End Sub
Figure 12.3. The Letter Entry screen.
The wordDelLineWith and wordReplace methods simplify the rest of the code. You use the wordDelLineWith method to find a line containing a given string and delete it. A side effect of the search and delete is that the insertion point is positioned at the
beginning of the old string. The wordReplace method takes two arguments; one is the target string to search for, and the other is the replacement string.
You might notice that the wordDelLineWith method uses named parameters to call the WordBasic EditFind statement, but the wordReplace method simply uses the parameters with no names. Both are valid ways of creating WordBasic statements. When using the
no-name style, remember to provide a value for every parameter.
The application created in the preceding example follows this sequence of events:
This application is very basic, but it does demonstrate how to access WordBasic. If you want additional information about WordBasic, look at the help file provided with Microsoft Word. Additional information is available on the Internet at the Microsoft
World Wide Web site.
Visual Basic programs don't have to use Microsoft Word to print; they can use the Printer object. When Visual Basic is first started, the Printer object is connected to the default
Windows printer. This means that you don't need to initialize this object. The Printer object encapsulates a lot of functionality in one place and is an excellent example of how objects can make difficult programming easier.
Printing to a piece of paper is significantly different than displaying information on a form on a computer screen. Although Visual Basic has come a long way in achieving device independence, dealing with a printer requires some special attention. Here
is a short list of things to keep in mind:
For the most part, Windows will isolate you from these errors when you use the Print Manager. The Print Manager is responsible for handling errors that arise during printing. In order to address the last concern, printing in Visual Basic takes place on
a job by job basis. Each job consists of one unit of work (for example, one document or chart) that is sent to the Windows print queue. After the entire job has been sent to the queue, Windows takes care of actually printing it by sending the job to the
printer.
Before looking at the Printer object in detail, it may be useful to look at a simple example of how the Printer object is used in a Visual Basic project. The example in this section uses three methods of the Printer object: Print, NewPage, and EndDoc.
The syntax of the Print method is as follows:
Printer.Print outputlist
The outputlist parameter can be any combination of strings, functions, or variables. In short, you can place any valid expression after the Print method and its value will be printed. The NewPage and EndDoc methods take no arguments. You use the
NewPage method to eject a page, reset the print position, and increment the Printer.Page property. You use EndDoc to tell the Print Manager that a print job has been transferred to the print queue and is ready for printing.
The following three lines will print the words "Hello, World!" at the top of the paper, eject the page, and end the print job.
Printer.Print "Hello, World!" Printer.NewPage Printer.EndDoc
The Print method supports the Tab() and Spc() functions that may already be familiar to you. You use the Tab() function to move the print position to a specific horizontal location. You use the Spc() function to insert a specific number of spaces into
the print line. The following example shows the difference:
Printer.Print "000000000111111111122222222223" Printer.Print "123456789012345678901234567890" Printer.Print "Hello, World!"; Tab(15); "Visual Basic" Printer.Print "Hello, World!"; Spc(15); "Visual Basic" Printer.NewPage Printer.EndDoc
The printed output should look like the following:
000000000111111111122222222223 123456789012345678901234567890 Hello, World! Visual Basic Hello, World! Visual Basic
You can see that the third line, which uses the Tab() function, starts the "Visual Basic" string at print position 15, and the fourth line, which uses the Spc() function, starts the "Visual
Basic" string at print position 29.
You use the semi-colons to indicate that no space should be inserted between the item just printed and the next item. This is true even if items are on a separate line of code.
The Printer object has a large amount of methods and properties defined for it. Table 12.2 shows all of the methods of the Printer object. Table 12.3 shows all the properties for this object.
Method |
Description |
Circle |
Draws a circle, ellipse, or arc on an object. If you want the graphic to be filled, set the Printer.FillColor and Printer.FillStyle properties. |
EndDoc |
Informs Windows that the current print job is finished and that printing should begin. |
KillDoc |
If KillDoc is executed before EndDoc, then the entire print job is deleted. |
Line |
Draws a line or box on the page. The line is affected by the DrawWidth, DrawMode, and DrawStyle properties. |
NewPage |
Ejects the page and resets the print position. Also, increments the Printer object's Page property. |
PaintPicture |
Draws the contents of a graphics file. The supported graphics formats are BMP, WMF, EMF, ICO, and DIB. |
|
Prints any expression. |
PSet |
Draws a point. You can change the size of the point by using the DrawWidth property. When DrawWidth is greater than 1, the point is centered on the specified coordinates. The DrawMode and DrawStyle properties also affect the point. You can erase a point by using the BackColor property as the color parameter. |
Scale |
Defines the coordinate system used for specifying locations on the page. |
ScaleX, ScaleY |
Converts from one coordinate system to another. |
TextHeight |
Returns the height of a string. If the string contains multiple lines, the cumulative height is returned. |
TextWidth |
Returns the width of a string. If the string contains multiple lines, the width of the longest line is returned. |
Property |
Description |
ColorMode |
If you set this property to vbPRCMMonochrome, then the printer will print in black and white. If you set this property to vbPRCMColor, then the printer will print in color. The default value depends on the printer driver. |
Copies |
The number of copies of a job to print. Remember that if more than one copy is needed, you may need to collate the pages. |
CurrentX, CurrentY |
The current horizontal (CurrentX) or vertical (CurrentY) coordinates for printing. |
DeviceName |
The name of the currently selected printer. |
DrawMode |
This property determines the appearance of output produced by a graphics method or the appearance of a Shape or Line control. |
DrawStyle |
This property determines the line style produced by graphics methods. The possibilities are Solid, Dash, Dot, Dash-Dot, Dash-Dot-Dot, Transparent, and Inside Solid. If DrawWidth is more than 1, the first five options all produce a solid line. |
DrawWidth |
This property determines the line width produced by graphics methods. |
DriverName |
The name of the printer driver for the currently selected printer. |
Duplex |
This property controls the use of two-sided printing. |
FillColor |
This property controls the color used to fill lines and circles. |
FillStyle |
This property controls the pattern used to fill shapes, lines, and circles. |
Font |
This property controls the font used to display text. You set it by using the Font object, which is discussed later in this chapter. |
FontBold |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
FontCount |
The number of fonts available in the printer. |
FontItalic |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
FontName |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
Fonts(x) |
This property is a list of the font names available for the printer. It works in conjunction with the FontCount property. |
FontSize |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
FontStrikethru |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
FontTransparent |
This property controls whether background text and graphics are displayed in the spaces around characters. Changing this property does not affect items already drawn. |
FontUnderline |
This property is included for backwards compatibility and should not be used. Use the Font property instead. |
ForeColor |
The foreground color of items to be printed. |
hDC |
The handle to the device context of the printer. |
Height |
The physical height of the paper. If set at run time, it will supersede the PaperSize property. |
Orientation |
If this property is equal to vbPRORPortrait, then items are printed with the long edge at the left. If this property is equal to vbPRORLandscape, then items are printed with the short edge at the left. |
Page |
The current page number. It is incremented when the NewPage method is run or the text being printed will not fit on the current page. Graphic items will be clipped and will not cause a new page to eject. |
PaperBin |
The bin number where the pages being printed should be taken from. |
PaperSize |
The size of the paper being printed. Setting the Height or Width property of the printer automatically sets PaperSize to be user-defined. |
Port |
The name of the port that the printer will be using. |
PrintQuality |
The resolution of the printer. You can set it to vbPRPQDraft, vbPRPQLow, vbPRPQMedium, vbPRPQHigh, or the actual resolution. |
ScaleHeight |
The number of units for the vertical measurement of the interior of an object. |
ScaleLeft |
The horizontal coordinate for the next print operation. |
ScaleMode |
The unit of measurement for coordinates. You can set it to twips, points, pixels, and other values. |
ScaleTop |
The vertical coordinate for the next print operation. |
ScaleWidth |
The number of units for the horizontal measurement of the interior of an object. |
TrackDefault |
Determines whether the Printer object changes the printer it is connected to if the user changes the default printer setting in the Control Panel or a Print dialog box. |
TwipsPerPixelX |
The number of twips per pixel in the horizontal direction. |
TwipsPerPixelY |
The number of twips per pixel in the vertical direction. |
Width |
The physical width, in twips, of the paper. If set at run time, it will supersede the PaperSize property. |
Zoom |
The percentage by which printed output is to be scaled up or down. The printer driver, not Windows, handles this activity. Be-fore using this property, make sure your printer driver supports it. |
This section explains how to let the user abort the printing process. You do this by invoking the KillDoc method when the user clicks on a Cancel button.
To run the example program in Listing 12.1, follow these steps:
Dim printingCancelled As Boolean Private Sub Command1_Click() printingCancelled = False For i = 1 To 500 DoEvents If printingCancelled = True Then printingCancelled = False Exit For End If Label1.Caption = "Printing " & i Printer.Print i Next i End Sub Private Sub Command2_Click() Printer.KillDoc printingCancelled = True End Sub Private Sub Form_Load() Label1.Left = 100 Label1.TOP = 100 Label1.Height = 200 Label1.Caption = "" Command1.Left = 100 Command1.TOP = 400 Command1.Caption = "Start" Command2.Left = 1600 Command2.TOP = 400 Command2.Caption = "Cancel" Form1.Caption = "Visual Basic Printing Test" Form1.Height = 2000 Form1.Width = 4000 End Sub
You can start the printing process by clicking on the Start button. The label will indicate what number is currently being printed so that you know that something is occurring. You can stop the printing at anytime by pressing the Cancel button.
This example demonstrates a couple of important points. One is that the printing method needs to call the DoEvents method so that Windows gets a chance to process that Cancel request. In fact, if the DoEvents method is not called, the label caption will
not be updated either. The other is that the printing loop needs a variable (printingCancelled) to indicate that the printing should stop.
The look of printed text is controlled by the Font object. This object has no methods, only properties. Table 12.4 lists these properties.
Property |
Description |
Bold |
Determines whether text is Bold. |
Italic |
Determines whether text is italicized. |
Name |
Specifies the name of the typeface to be used (For example, Arial or Courier). |
Size |
Specifies the size of the text to be used, measured in points. |
StrikeThrough |
Determines whether text is |
Underline |
Determines whether text is underlined. |
Weight |
Specifies the thickness of the strokes that make up the text. Valid values are 400 (regular) or 700 (bold). |
You can set the printer for bold text with the following line of code:
Printer.Font.Bold = True
You can set the rest of the properties in a similar manner. To find out which fonts are supported by the default printer, use the following code block:
Printer.Copies = 1 For i = 1 To Printer.FontCount - 1 Printer.Print i; ":"; Printer.Fonts(i) Next i Printer.EndDoc
This code prints a list of all of the typefaces supported by your default printer.
This section examines how to use some of the methods of the Printer object. There are too many methods to discuss them all, but these examples will give you a good head start.
The first example shows how to use the PaintPicture method. You can use this method to print any BMP, WMF, EMF, ICO, or DIB file. The first step is to place a PictureBox control on a form. Then, run the code in Listing 12.3 when you want to print the
control's contents.
Picture1.picture = LoadPicture("ICONS\COMPUTER\TRASH02A.ICO") Printer.Copies = 1 startX = 100 startY = 100 Printer.PaintPicture Picture1.picture, _ startX, startY, Picture1.Width, Picture1.Height nextY = startY + Picture1.Height + 200 Printer.PaintPicture Picture1.picture, _ startX, nextY, Picture1.Width * 2, Picture1.Height * 2 nextX = startX + Picture1.Width * 2 nextY = nextY + (Picture1.Height * 4) + 200 Printer.PaintPicture Picture1.picture, _ nextX, nextY, Picture1.Width * -2, Picture1.Height * -2 Printer.EndDoc Printer.Copies = 1 startX = 100 startY = 100 Printer.PaintPicture Picture1.picture, _ startX, startY, Picture1.Width, Picture1.Height nextY = startY + Picture1.Height + 200 Printer.PaintPicture Picture1.picture, _ startX, nextY, Picture1.Width * 2, Picture1.Height * 2 nextX = startX + Picture1.Width * 2 nextY = nextY + (Picture1.Height * 4) + 200 Printer.PaintPicture Picture1.picture, _ nextX, nextY, Picture1.Width * -2, Picture1.Height * -2 Printer.EndDoc
To center text, you must use the TextWidth method of the Printer object in order to account for proportional fonts. The centerText method in Listing 12.4 shows how to find the print position needed to start printing. First, the center point of the page
is found and then half of the width of the string parameter is subtracted. This calculation results in the starting print position. If you need to manipulate the font, such as changing the typeface or point size, be sure to do it before calling the
TextWidth method.
Private Sub centerText(h As Integer, str As String) pageMiddle = Printer.ScaleWidth / 2 Printer.CurrentX = pageMiddle - (Printer.TextWidth(str) / 2) Printer.CurrentY = h Printer.Print str End Sub Private Sub Form_Click() Printer.Copies = 1 centerText 1440, "This text is centered." centerText 2880, "This text is centered also." Printer.EndDoc End Sub
This chapter explained how to display and interact with the Print dialog box, how to manipulate Microsoft Word, and how to use the Printer object.
Using Microsoft Word to handle print chores is a very powerful technique. You can incorporate any or all of Word's features inside your own program. Additional uses of Word might be to print labels, create tables from databases, or to automatically
create indexes.
Advanced usage of the Printer object usually takes advantage of its dual nature. You can use the Print method to do text-based printer, but you can also use Line, Circle, PSet, and PaintPicture methods to do graphic-based printing.